import java.util.ArrayList;
import java.util.List;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class MultiThread extends MonteCarlo {
    @Override
    public double monteCarloStandardOption(char CallPutFlag, final double S, final double X, double T, double r, double b, double v, final int nSteps, int nSimulations) {
        double dt;
        double sum = 0;
        final double drift;
        final double vSqrdt;
        final int z;
        
        dt = T/nSteps;
        drift = ((b - Math.pow(v,2)) / 2) * dt;
        vSqrdt = v * Math.sqrt(dt);
        if (CallPutFlag == 'c'){
            z = 1;
        }
        else if (CallPutFlag == 'p'){
            z = -1;
        }
        else{
            z=0;
        }
        final List<Callable<Double>> partitions = new ArrayList<>();
        for(int i=0; i< nSimulations; i++) {
            partitions.add(new Callable<Double>() {
                @Override
                public Double call() throws Exception {
                    final Random random = new Random();
                    return MonteCarlo.simulation(z,S,X,drift,vSqrdt,nSteps,random);
                }
            });
        }
        final ExecutorService executorPool = Executors.newFixedThreadPool(40);    
        List<Future<Double>> valueOfSimulations = null;
            try {
                valueOfSimulations = executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
            } catch (InterruptedException ex) {
                System.out.println("Erreur");
            }
        for(final Future<Double> valueOfASim : valueOfSimulations){ 
                try {
                    sum += valueOfASim.get();
                } catch (    InterruptedException | ExecutionException ex) {
                    System.out.println("Erreur");
                }
        }
        executorPool.shutdown();
        return Math.exp(-r * T) * (sum/nSimulations);
    }
}
